home *** CD-ROM | disk | FTP | other *** search
/ L' Effet Pommier 3 / L'Effet Pommier - Volume 03.iso / Programmation / gray image 2.1 / color_coordinates.cc next >
Text File  |  1995-07-30  |  10KB  |  380 lines

  1. // This may look like C code, but it is really -*- C++ -*-
  2. /*
  3.  *************************************************************************
  4.  *
  5.  *         Demostrating representation of the color picture
  6.  *             in various color coordinates
  7.  *
  8.  * There are a lot of color coordinates schemes besides the familiar
  9.  * RGB. The present programs reads an image (written in the PPM,
  10.  * portable pixel map, which is RGB color coded) and displays the image
  11.  * in color as well as its three color projections (coordinates)
  12.  * for a variety of color coordinate systems.
  13.  * See the comments below for the color coordinates.
  14.  *
  15.  *************************************************************************
  16.  */ 
  17.  
  18. #include "image.h"
  19. #include <fstream.h>
  20.  
  21.  
  22. /*
  23.  *------------------------------------------------------------------------
  24.  *          Representation of the color image
  25.  */
  26.  
  27. class ColorImage {
  28.  
  29. protected:
  30.   char * color_scheme_label;        // Label for the color scheme
  31.   char * coord_labels[3];        // Labels for the color coordinates
  32.   IMAGE * color_proj[3];        // 3 color projections as gray-scale
  33.                     // images
  34.   ColorImage(void) {}            // All actual creation is to be done
  35.                     // in siblings
  36.  
  37. public:
  38.   ~ColorImage(void);
  39.  
  40.   char * q_color_scheme_label(void) const     { return color_scheme_label; }
  41.   char * q_coord_label(const int i) const
  42.   { assert( i>=0 && i<3 ); return coord_labels[i]; }
  43.  
  44.   IMAGE& proj_image(const int i)
  45.   { assert( i>=0 && i<3 ); return *color_proj[i]; }
  46.  
  47.   void display_projections(void) const;
  48. };
  49.  
  50.  
  51.                 // Common destructor
  52. ColorImage::~ColorImage(void)
  53. {
  54.   assert( color_scheme_label != 0 && color_proj[0] != 0 );
  55.   delete color_scheme_label;
  56.   register int i;
  57.   for(i=0; i<3; i++)
  58.     delete coord_labels[i], delete color_proj[i];
  59. }
  60.  
  61.                 // Display color projections of the image
  62. void ColorImage::display_projections(void) const
  63. {
  64.   char buffer[200];
  65.   register int i;
  66.   for(i=0; i<3; i++)
  67.   {
  68.     sprintf(buffer,"%s/%s",color_scheme_label,coord_labels[i]);
  69.     (*color_proj[i]).display(buffer);
  70.   }
  71. }
  72.  
  73. /*
  74.  *------------------------------------------------------------------------
  75.  *            RGB image and reading it
  76.  */
  77.  
  78. class RGB_image : public ColorImage {
  79.  
  80. public:
  81.                 // Read the color image from the ppm file
  82.   RGB_image(const char * ppm_file_name);
  83.   ~RGB_image(void) {}        // Nothing special in destruction
  84. };
  85.  
  86. RGB_image::RGB_image(const char * ppm_file_name)
  87. {
  88.   message("\nReading the PPM image from '%s'...\n",ppm_file_name);
  89.   ifstream fp(ppm_file_name);
  90.   char c;
  91.   if( !fp.get(c) || c != 'P' || !fp.get(c) || c != '6' )
  92.     _error("Unable to read the correct header 'P6' of the compact PPM");
  93.  
  94.   int width, height, depth;
  95.   fp >> width >> height >> depth;
  96.   depth = log2(depth+1);        // Convert from maxvalue to depth
  97.   if( !fp.get(c) || c != '\n' )
  98.     _error("Bad symbol %xh occured after the depth specification",c);
  99.  
  100.   color_scheme_label = strdup("RGB NTSC");
  101.   coord_labels[0] = strdup("Red");
  102.   coord_labels[1] = strdup("Green");
  103.   coord_labels[2] = strdup("Blue");
  104.  
  105.   register int pi;
  106.   for(pi=0; pi<3; pi++)
  107.     color_proj[pi] = new IMAGE(height,width,depth);
  108.  
  109.   message("\nReading the RGB pixel matrix for %dx%dx%d color image ...",
  110.       width,height,depth);
  111.   register int i,j;
  112.   for(i=0; i<height; i++)
  113.     for(j=0; j<width; j++)
  114.       if( !fp.get(c) || ((*color_proj[0])(i,j) = c,0) ||
  115.       !fp.get(c) || ((*color_proj[1])(i,j) = c,0) ||
  116.       !fp.get(c) || ((*color_proj[2])(i,j) = c,0) )
  117.     _error("Error reading the PPM file",(perror(""),0));
  118.   message("Done\n\n");
  119. }        
  120.  
  121. /*
  122.  *------------------------------------------------------------------------
  123.  *    Cobversion from RGB to other tristimulus color system
  124.  *
  125.  * See Pratt, Digital Image processing, Appendix 2
  126.  * Note, that elements of the conversion matrix are float point numbers
  127.  * in [0,2]. We represent them as rational numbers with the common
  128.  * denominator specified separately.
  129.  *
  130.  */
  131.  
  132. struct TristimulusSystem {
  133.  
  134.   char * label;                // Label of the system
  135.   char * tristimulus_labels[3];        // Labels for the tristimulus
  136.   int  conv_matrix [3] [3];        // Conversion matrix from RGB
  137.   int  common_denominator;
  138. };
  139.  
  140.  
  141. class TristimulusImage : public ColorImage {
  142.  
  143. public:
  144.                 // Convert from RGB to other system
  145.   TristimulusImage(const RGB_image& rgbim, const TristimulusSystem& conv);
  146.   ~TristimulusImage() {}
  147. };
  148.  
  149.                 // Convert from RGB to other system
  150. TristimulusImage::TristimulusImage
  151. (const RGB_image& rgbim, const TristimulusSystem& conv)
  152. {
  153.   color_scheme_label = strdup(conv.label);
  154.  
  155.   register int i;
  156.   for(i=0; i<3; i++)
  157.     coord_labels[i] = strdup(conv.tristimulus_labels[i]),
  158.     color_proj[i] = new IMAGE(*rgbim.color_proj[0]);
  159.  
  160.                     // Actual conversion
  161.   register int j;
  162.   for(i=0; i<(*color_proj[0]).q_nrows(); i++)
  163.     for(j=0; j<(*color_proj[0]).q_ncols(); j++)
  164.     {
  165.       const int rval = (*rgbim.color_proj[0])(i,j);
  166.       const int gval = (*rgbim.color_proj[1])(i,j);
  167.       const int bval = (*rgbim.color_proj[2])(i,j);
  168.       (*color_proj[0])(i,j) = ( rval*conv.conv_matrix[0][0] +
  169.                  gval*conv.conv_matrix[0][1] +
  170.                  bval*conv.conv_matrix[0][2] ) 
  171.                / conv.common_denominator;
  172.       (*color_proj[1])(i,j) = ( rval*conv.conv_matrix[1][0] +
  173.                 gval*conv.conv_matrix[1][1] +
  174.                 bval*conv.conv_matrix[1][2] ) 
  175.                   / conv.common_denominator;
  176.       (*color_proj[2])(i,j) = ( rval*conv.conv_matrix[2][0] +
  177.                 gval*conv.conv_matrix[2][1] +
  178.                 bval*conv.conv_matrix[2][2] ) 
  179.                   / conv.common_denominator;
  180.     }
  181. }
  182.  
  183.  
  184. typedef void (*ProcessingFunction)(const RGB_image& image,
  185.                    const void * argument);
  186.  
  187. static void convert_to_tristimulus_system
  188.     (const RGB_image& rgb_image, const TristimulusSystem * conv)
  189. {
  190.   TristimulusImage new_image(rgb_image,*conv);
  191.   new_image.display_projections();
  192. }
  193.  
  194. /*
  195.  *------------------------------------------------------------------------
  196.  *        Conversion from tristimulus to the
  197.  *        luminance-chrominance color system
  198.  *
  199.  * If T1, T2, and T3 are three tristimulus values in some coordinate
  200.  * system, then chromacity values can be defined as follows
  201.  *
  202.  *    t1 = T1/(T1+T2+T3)
  203.  *    t2 = T2/(T1+T2+T3)
  204.  * 
  205.  * Chrominance values, which are normally within the range [0,1] are
  206.  * multiplied by 255 for display
  207.  *
  208.  */
  209.  
  210. static void convert_to_chrominance
  211.     (const RGB_image& rgb_image, const TristimulusSystem * conv)
  212. {
  213.   TristimulusImage T_image(rgb_image,*conv);
  214.   IMAGE t1(T_image.proj_image(0));        // Chrominance components
  215.   IMAGE t2(t1);
  216.   t1 = T_image.proj_image(0);
  217.   t2 = T_image.proj_image(1);
  218.   IMAGE& T3 = T_image.proj_image(2);
  219.  
  220.   register int i,j;
  221.   for(i=0; i<t1.q_nrows(); i++)
  222.     for(j=0; j<t1.q_ncols(); j++)
  223.     {
  224.       const int T3v = T3(i,j);
  225.       register GRAY& t1r = t1(i,j);
  226.       register GRAY& t2r = t2(i,j);
  227.       register int sum = t1r + t2r + T3v;        // T1+T2+T3
  228.       if( sum == 0 )
  229.     t1r = 0, t2r = 0;                // Black pixel
  230.       else
  231.     t1r = (t1r << 8) / sum,
  232.         t2r = (t2r << 8) / sum;
  233.     }
  234.  
  235.   char buffer[200];
  236.   sprintf(buffer,"%s/t1 chrominance",T_image.q_color_scheme_label());
  237.   t1.display(buffer);
  238.   sprintf(buffer,"%s/t2 chrominance",T_image.q_color_scheme_label());
  239.   t2.display(buffer);
  240. }
  241.  
  242.  
  243. /*
  244.  *------------------------------------------------------------------------
  245.  *                 Root modules
  246.  */
  247.  
  248. struct MenuItem {
  249.   char * label;
  250.   ProcessingFunction executor;
  251.   void * argument;
  252. };
  253.  
  254. static MenuItem Menu [] =
  255. {
  256.   { "C.I.E Spectral Primary Color Coordinate System",
  257.     convert_to_tristimulus_system,
  258.     &(TristimulusSystem)
  259.     { "CIE primary RGB",
  260.       {"Monochrom Red", "Monochrom Green", "Monochrom Blue"},
  261.       { {1167, -146, -151},
  262.         { 114,  753,  159},
  263.         {  -1,   59, 1128}
  264.       },
  265.       1000
  266.     },
  267.   },
  268.  
  269.   { "X-Y-Z system",
  270.     convert_to_tristimulus_system,
  271.     &(TristimulusSystem)
  272.     { "XYZ", {"X", "Y - luminance", "Z"},
  273.       { {607, 174,  201},
  274.         {299, 587,  114},
  275.         {  0,  66, 1117}
  276.       },
  277.       1000
  278.     }
  279.   },
  280.  
  281.   { "U-V-W Uniform Chromacity Scale",
  282.     convert_to_tristimulus_system,
  283.     &(TristimulusSystem)
  284.     { "UVW", {"U", "V - luminance", "W"},
  285.       { {405, 116,  133},
  286.         {299, 587,  114},
  287.         {145, 827,  627}
  288.       },
  289.       1000
  290.     }
  291.   },
  292.  
  293.   { "Y-I-Q NTSC Transmission Color Coordinate system",
  294.     convert_to_tristimulus_system,
  295.     &(TristimulusSystem)
  296.     { "YIQ - NTSC TV signal", {"Y - luminance", "I-chromatic", "Q-chromatic"},
  297.       { {299,  587,  114},
  298.         {596, -274, -322},
  299.         {211, -523,  312}
  300.       },
  301.       1000
  302.     }
  303.   },
  304.  
  305.   { "x-y chrominance system",
  306.     convert_to_chrominance,
  307.     &(TristimulusSystem)
  308.     { "XYZ", {"X", "Y - luminance", "Z"},
  309.       { {607, 174,  201},
  310.         {299, 587,  114},
  311.         {  0,  66, 1117}
  312.       },
  313.       1000
  314.     }
  315.   },
  316.  
  317.   { "u-v Uniform Chromacity Scale",
  318.     convert_to_chrominance,
  319.     &(TristimulusSystem)
  320.     { "UVW", {"U", "V - luminance", "W"},
  321.       { {405, 116,  133},
  322.         {299, 587,  114},
  323.         {145, 827,  627}
  324.       },
  325.       1000
  326.     }
  327.   }
  328.  
  329. };
  330.  
  331. main(const int argc, const char * argv[])
  332. {
  333.   cout << "\n\n\t\tDisplay the color components of the color image in various"
  334.           "\n\t\t\t\tcolor coordinate systems\n\n";
  335.  
  336.   if( argc != 2 )
  337.     message("\nUsage: color_coordinates image_file_in_PPM_format\n"),
  338.     exit(4);
  339.  
  340.   {                    // Display the image as it is
  341.     char buffer[200];
  342.     sprintf(buffer,"xv %s &",argv[1]);
  343.     cout << "\nDisplaying the image with the command <" << buffer
  344.          << ">\n";
  345.     system(buffer);
  346.   }
  347.  
  348.   RGB_image rgb_image(argv[1]);
  349.   rgb_image.display_projections();
  350.  
  351.                     // Handling menus
  352.   for(;;)
  353.   {
  354.     const int no_choices = sizeof(Menu)/sizeof(MenuItem);
  355.     register int i;
  356.  
  357.     sleep(2);
  358.     cout << "\n\n\t\t\t\tMenu\n";        // Display the menu
  359.     for(i=0; i<no_choices; i++)
  360.       cout << "\t" << i+1 << ". " << Menu[i].label << "\n";
  361.  
  362.  
  363.     int choice;
  364.     for(;;)
  365.     {
  366.       cout << "Enter the number of your choice or 0 to quit\n";
  367.       cin >> choice;
  368.       if( choice == 0 )
  369.     exit(0);
  370.       else if( choice > 0 && choice <= no_choices )
  371.     break;
  372.       cout << "\nYou entered invalid number. Please enter the number "
  373.           "1.." << no_choices << " or 0 to quit\n";
  374.     }
  375.     i = choice - 1;
  376.     Menu[i].executor(rgb_image,Menu[i].argument);
  377.   }
  378. }
  379.  
  380.